home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 001a / jmod310.zip / JMODEM_E.C < prev    next >
Text File  |  1991-11-30  |  20KB  |  320 lines

  1. /****************************************************************************/
  2. /*   FILE JMODEM_E.C                                                        */
  3. /*   Created 11-JAN-1990                 Richard B. Johnson                 */
  4. /*                                       405 Broughton Drive                */
  5. /*                                       Beverly, Massachusetts 01915       */
  6. /*                                       BBS (508) 922-3166                 */
  7. /*   open_chan();                                                           */
  8. /*   close_chan();                                                          */
  9. /*   read_chan();                                                           */
  10. /*   write_chan();                                                          */
  11. /*                      Communications I/O procedures                       */
  12. /*  These procedures will have to be replaced for JMODEM to execute on      */
  13. /*  a system other than a MS_DOS computer. They are VERY hardware-specific. */
  14. /*  These procedures are grouped so that they can be replaced as a unit.    */
  15. /*  You must replace the following:                                         */
  16. /*  (1) OPEN a communications channel.                                      */
  17. /*  (2) CLOSE the opened channel.                                           */
  18. /*  (3) READ [variable] bytes from the channel.                             */
  19. /*  (4) WRITE [variable] bytes to the channel.                              */
  20. /*                                                                          */
  21. /*  When attempting to READ bytes, some sort of time-out must be provided   */
  22. /*  within the routine to prevent a "wait-forever" syndrome.                */
  23. /*                                                                          */
  24. /*  VAX/VMS, QIO routines are ideal!                                        */
  25. /*                                                                          */
  26. /****************************************************************************/
  27. #include <stdio.h>                          /* For FILE structure           */
  28. #include <conio.h>                          /* For _inp() and _outp()       */
  29. #include <dos.h>                            /* For _enable() and _disable() */
  30. #include "jmodem.h"                         /* JMODEM equates               */
  31. #include "uart.h"                           /* 8250 UART equates            */
  32. #if defined (TURBOC)
  33.     #include <mem.h>
  34.     #define  _enable        enable
  35.     #define  _disable       disable
  36.     #define  _dos_setvect   setvect
  37.     #define  _dos_getvect   getvect
  38. #else
  39.     #include <memory.h>                     /* _memcpy();                   */
  40. #endif
  41. /****************************************************************************/
  42. /*                     Structures and templates                             */
  43. /****************************************************************************/
  44. typedef struct  {
  45.         word base;                          /* Base port address            */
  46.         word mask;                          /* Interrupt controller mask    */
  47.         word int_num;                       /* Interrupt number             */
  48.         } PORTS;
  49.  
  50. PORTS port_pars[] =     {
  51.                         {
  52.                         0x3F8   ,           /* Base port address    COM1    */
  53.                         0xEF    ,           /* IRQ4 11101111B       COM1    */
  54.                         0x0C    ,           /* Interrupt number             */
  55.                         }       ,
  56.                         {
  57.                         0x2F8   ,           /* Base port address    COM2    */
  58.                         0xF7    ,           /* IRQ3 11110111B       COM2    */
  59.                         0x0B    ,           /* Interrupt number             */
  60.                         }       ,
  61.                         {
  62.                         0x3E8   ,           /* Base port address    COM3    */
  63.                         0xEF    ,           /* IRQ4 11101111B       COM3    */
  64.                         0x0C    ,           /* Interrupt number             */
  65.                         }       ,
  66.                         {
  67.                         0x2E8   ,           /* Base port address    COM4    */
  68.                         0xF7    ,           /* IRQ3 11110111B       COM4    */
  69.                         0x0B    ,           /* Interrupt number             */
  70.                         }
  71.                         };
  72. /****************************************************************************/
  73. /*                          Global allocation                               */
  74. /****************************************************************************/
  75. byte *write_ptr;                             /* Interrupt buffer            */
  76. byte *read_ptr;                              /* Interrupt buffer            */
  77. byte *buff_limit;                            /* End of interrupt buffer     */
  78. word port;                                   /* Port number                 */
  79. word old_mask;                               /* Old interrupt control mask  */
  80. word old_ier;                                /* Old interrupt enable regis  */
  81. word old_stat;                               /* Modem status for flow-contr */
  82. word carrier;                                /* Carrier detect              */
  83. word timer;                                  /* Global timer                */
  84. word hardware_port;                          /* Physical port               */
  85. /****************************************************************************/
  86. /*                        Function prototypes                               */
  87. /****************************************************************************/
  88. void interrupt far fatal_abort(void);        /* Abort vector                */
  89. void interrupt far com_int(void);            /* Interrupt service routine   */
  90. void interrupt far tim_int(void);            /* Timer interrupt             */
  91. void (interrupt far *old_tim)();             /* Pointer to old timer intr.  */
  92. void (interrupt far *old_com)();             /* Pointer to old commu intr.  */
  93. void (interrupt far *old_brk)();             /* Pointer to old break key.   */
  94. /****************************************************************************/
  95. /*                 Open the communications channel                          */
  96. /*                                                                          */
  97. /*    Under MS-DOS this involves saving the com-port vector, interrupt      */
  98. /*    controller mask, and the user-tick timer vector.                      */
  99. /*    New vectors and masks and patched for the communications interrupt    */
  100. /*    service routine and the local timer. These vectors will be restored   */
  101. /*    within the CLOSE channel routine.                                     */
  102. /*                                                                          */
  103. /****************************************************************************/
  104. word open_chan (word user_port)          /* Port offset ( 1-4 )             */
  105. {
  106.     short i;
  107.     buff_limit = int_buffer + DAT_LEN-1; /* Set up buffer end pointer       */
  108.     flush();                             /* Initialize the interrupt buffer */
  109.     if (user_port > 4)                   /* If absolute port and IRQ        */
  110.     {
  111.         port_pars[0].base =
  112.             (user_port & 0x0FFF);        /* Extract absolute port           */
  113.         port_pars[0].int_num =           /* Use as a temporary variable     */
  114.             (user_port >> 12);           /* Extract the IRQ number          */
  115.         port_pars[0].mask =              /* Create the controller mask      */
  116.             ((~(0x01 << port_pars[0].int_num)) & 0xFF);
  117.         port_pars[0].int_num += 0x08;    /* IRQ number to ABS interrupt     */
  118.         user_port = 1;                   /* For following instruction       */
  119.     }
  120.     user_port--;                         /* Convert to an offset            */
  121.     hardware_port =
  122.        port_pars[user_port].base;        /* Set hardware port               */
  123.     old_ier  = inp(hardware_port +IER);  /* Get interrupt enable regis      */
  124.     old_brk  = _dos_getvect(0x1B);       /* Get old break key vector        */
  125.     old_mask = inp(0x21);                /* Save old interrupt mask         */
  126.     old_tim  = _dos_getvect(0x1C);       /* Get old DOS timer-tick vector   */
  127.     old_com  = _dos_getvect(
  128.        port_pars[user_port].int_num);    /* Get old communications vector   */
  129.     _dos_setvect(0x1B,fatal_abort);      /* Set fatal abort vector (1)      */
  130.     _dos_setvect(0x23,fatal_abort);      /* Set fatal abort vector (2)      */
  131.     _dos_setvect(0x1C,tim_int);          /* Set new timer interrupt         */
  132.     _dos_setvect(
  133.        port_pars[user_port].int_num,     /* Set new communications vector   */
  134.        com_int);
  135.     outp(0x21,old_mask &
  136.        port_pars[user_port].mask);       /* Set interrupt enable mask       */
  137.     outp(hardware_port+MCR, MOD_ENA);    /* Turn on DTR, RTS, IRQ enable    */
  138.     outp(hardware_port+IER, IER_ERBFI);  /* Enable received data available  */
  139.     for (i=0; i<8; i++)                  /* Edge-triggering, read the ports */
  140.         inp(hardware_port + i);          /* Port to clear                   */
  141.     outp(0x20,0x20);                     /* Reset the hardware controller   */
  142.     timer=9;                             /* 1/2 second wait                 */
  143.     while (timer);                       /* Wait 1/2 second                 */
  144.     flush();                             /* Clear interrupt buffer again    */
  145.     i = inp(hardware_port+MSR);          /* Get current modem status        */
  146.     old_stat = i & MSR_CHK;              /* Get current modem control       */
  147.     carrier  = i & MSR_RLSD;             /* Get any modem carrier           */
  148.     return JM_NRM;
  149. }
  150. /****************************************************************************/
  151. /*                 Close the communications channel                         */
  152. /*                                                                          */
  153. /*    Under MS-DOS this involves restoring the interrupt vectors and        */
  154. /*    controller mask that was saved during the OPEN routine.               */
  155. /*                                                                          */
  156. /****************************************************************************/
  157. word close_chan (word user_port)
  158. {
  159.     if (user_port > 4) user_port = 1;      /* Absolute port address         */
  160.     user_port--;                           /* Convert to an offset          */
  161.     outp(hardware_port+IER,old_ier);       /* Set old interrupt enable      */
  162.     outp(0x21,old_mask);                   /* Restore old interrupt mask    */
  163.     _dos_setvect(
  164.        port_pars[user_port].int_num,       /* Set old communications vector */
  165.        old_com);
  166.     _dos_setvect(0x1C,old_tim);            /* Set old timer interrupt       */
  167.     _dos_setvect(0x1B,old_brk);            /* Set old break interrupt       */
  168.     return JM_NRM;
  169. }
  170. /****************************************************************************/
  171. /*              Read from the communications channel                        */
  172. /*                                                                          */
  173. /*    This involves transferring data from the interrupt buffer and         */
  174. /*    maintaining the interrupt buffer pointers. A timeout is established.  */
  175. /*                                                                          */
  176. /****************************************************************************/
  177. word read_chan (word bytes,              /* Bytes requested                 */
  178.                 register byte *buffer)   /* Pointer to user's buffer        */
  179. {
  180.     word count;                          /* Byte count                      */
  181.     word avail;                          /* Bytes available                 */
  182.     timer = TIMOUT;                      /* Set initial timeout value       */
  183.     count = bytes;                       /* Set byte-count                  */
  184.  
  185.     while (count && timer)               /* If byte request or no timeout   */
  186.     {
  187.         avail = write_ptr - read_ptr;    /* Bytes available                 */
  188.         if (avail)                       /* If bytes available              */
  189.         {
  190.             if (avail > count)           /* If more bytes than we need      */
  191.                 avail = count;           /* Take only what we need          */
  192.             memcpy (buffer   ,           /* User's buffer                   */
  193.                     read_ptr ,           /* Interrupt buffer pointer        */
  194.                     avail)   ;           /* Copy to user's buffer           */
  195.             count -= avail;              /* Update count                    */
  196.             read_ptr +=avail;            /* Update read pointer             */
  197.             buffer   +=avail;            /* Update write pointer            */
  198.             timer = TIMOUT;              /* Set new timer value             */
  199.         }
  200.         _disable();                      /* Clear interrupts                */
  201.         if (read_ptr == write_ptr)       /* If no bytes available           */
  202.             read_ptr = write_ptr         /* Initialize the interrupt buffer */
  203.                      = int_buffer;
  204.         _enable();                       /* Enable interrupts               */
  205.     }
  206.     return(bytes - count);               /* Actual characters received      */
  207. }
  208. /****************************************************************************/
  209. /*                      Flush the interrupt buffer                          */
  210. /****************************************************************************/
  211. void flush()
  212. {
  213.     _disable();
  214.     read_ptr = write_ptr = int_buffer;   /* Initialize the interrupt buffer */
  215.     _enable();
  216. }
  217. /****************************************************************************/
  218. /*                      Communications transmit routine                     */
  219. /*    Write 'bytes' bytes from buffer to the UART. Don't return until done  */
  220. /*    unless the carrier failed or the hardware broke.                      */
  221. /****************************************************************************/
  222. word write_chan (word bytes,                  /* Bytes to send              */
  223.                  register byte *buffer)       /* Pointer to the buffer      */
  224. {
  225.     word status;
  226.     byte *sav_sta;
  227.     byte *old_sta;
  228.  
  229.     sav_sta = old_sta = syst.s_sta;           /* Save current status        */
  230.     timer = TIMOUT;
  231.     while ((bytes && timer) && !user_abort )  /* Bytes, no abort, no timout */
  232.     {
  233.         while (
  234.               ( status =                      /* Get modem status           */
  235.               ( inp (hardware_port+MSR)       /* from modem status register */
  236.                 & MSR_CHK )                   /* Check CTS and DSR only     */
  237.               ) != old_stat)                  /* If not the same as before  */
  238.         {                                     /* Flow control loop          */
  239.             if ( (status & MSR_RLSD )         /* ...check modem carrier     */
  240.                  != carrier)                  /* ... if not same as before  */
  241.                 {
  242.                     user_abort = 0x0FFFF;     /* Set the abort flag         */
  243.                     return JM_ABT;            /* ... and get out            */
  244.                 }
  245.             syst.s_sta = flow;                /* Set flow-control status    */
  246.             if ( syst.s_sta != old_sta )      /* If we haven't already      */
  247.             {
  248.                 screen (SCR_FLG,&syst);       /* Show flow-control status   */
  249.                 old_sta = syst.s_sta;         /* Flag that we did it        */
  250.             }
  251.         }
  252.     syst.s_sta = sav_sta;                     /* Set previous status        */
  253.     if ( syst.s_sta != old_sta )
  254.         {
  255.             screen (SCR_FLG,&syst);           /* Show previous status       */
  256.             old_sta = syst.s_sta;             /* Flag that we did it        */
  257.         }
  258.         status = inp(hardware_port+LSR);      /* Get line-status            */
  259.         if (status & LSR_THRE)                /* If TX holding reg empty    */
  260.         {
  261.             outp(hardware_port, *buffer++);   /* Send the byte              */
  262.             bytes--;                          /* Bump the byte-count        */
  263.             timer = TIMOUT;                   /* Set new timer-value        */
  264.         }
  265.     }
  266.     return JM_NRM;
  267. }
  268.  
  269. /******* The following interrupt service routines are in JMODEM_G.ASM *******/
  270. #ifdef DOIT_IN_C
  271. /****************************************************************************/
  272. /*                Communications adapter hardware interrupt                 */
  273. /*    This is very simple because we interrupt on receive only. Since we    */
  274. /*    must wait until the entire block has been received and checked be-    */
  275. /*    for doing anything else, the transmitter is polled.                   */
  276. /*                                                                          */
  277. /****************************************************************************/
  278. void interrupt far com_int()
  279. {
  280.     *write_ptr = (byte)
  281.         inp(hardware_port);                    /* Put byte in buffer        */
  282.     outp(0x20,0x20);                           /* Reset hardware controller */
  283.    if (write_ptr < buff_limit)                 /* Check buffer for overflow */
  284.         write_ptr++;                           /* Bump pointer if room      */
  285. }
  286. /****************************************************************************/
  287. /*                            Timer interrupt                               */
  288. /*    A WORD (timer) gets decremented every timer-tick if it is not already */
  289. /*    zero. This is used to set time-out values in the communication pro-   */
  290. /*    cedures so that a "wait-forever" can't occur.                         */
  291. /*                                                                          */
  292. /****************************************************************************/
  293. void interrupt far tim_int()
  294. {
  295.     if (timer)                             /* If NZ                         */
  296.         timer--;                           /* Bump the timer                */
  297.     outp(0x20,0x20);                       /* Reset the hardware controller */
  298.     _enable();                             /* Allow network interrupts      */
  299. #if !defined (TURBOC)
  300.     _chain_intr(old_tim);                  /* Go to old timer-tick routine  */
  301. #endif
  302. }
  303. #endif
  304. /****************************************************************************/
  305.  
  306. /****************************************************************************/
  307. /*                          A B O R T   trap                                */
  308. /*    Control-C and control-break vectors are set to point here so that     */
  309. /*    a user-break harmlessly sets a flag so that interrupt vectors may     */
  310. /*    properly restored upon program exit.                                  */
  311. /*                                                                          */
  312. /****************************************************************************/
  313. void interrupt far fatal_abort()
  314. {
  315.     user_abort = 0xFFFF;                              /* Set abort flag     */
  316.     timer = 0;                                        /* Provoke timout     */
  317. }
  318. /****************************************************************************/
  319. /******************** E N D   O F   M O D U L E *****************************/
  320.